#ifndef _PACK_READER_H_
#define _PACK_READER_H_

#include "net/net.h"

namespace pack {

class Reader {
public:
    Reader(net::IBuffer* buffer);
    ~Reader();

public:
    operator bool();

    Reader& operator>>(uint32_t& v);
    Reader& operator>>(std::string& v);

    Reader& operator>>(std::list<uint32_t>& v);
    Reader& operator>>(std::list<std::string>& v);

    template<typename T>
        Reader& operator>>(T& v);

    template<typename T>
        Reader& operator>>(std::list<T>& v);

    template<typename T>
        Reader& operator>>(std::vector<T>& v);

    template<typename T>
        Reader& operator>>(std::set<T>& v);

    template<typename T1, typename T2>
        Reader& operator>>(std::map<T1, T2>& v);

protected:
    bool is_good;

    net::IBuffer* buffer;
};

template<typename T>
Reader& Reader::operator>>(T& v) {
    v.Deserialize(buffer);
    return *this;
}

template<typename T>
Reader& Reader::operator>>(std::list<T>& v) {
    size_t size = 0;
    buffer->Read((char*)&size, sizeof(size_t));

    for(size_t i = 0; i < size; i++) {
        T temp;

        temp.Deserialize(buffer);
        v.push_back(temp);
    }

    return *this;
}

template<typename T>
Reader& Reader::operator>>(std::vector<T>& v) {
    size_t size = 0;
    buffer->Read((char*)&size, sizeof(size_t));

    for(size_t i = 0; i < size; i++) {
        T temp;

        this->operator>>(temp);
        v.push_back(temp);
    }

    return *this;
}

template<typename T>
Reader& Reader::operator>>(std::set<T>& v) {
    size_t size = 0;
    buffer->Read((char*)&size, sizeof(size_t));

    for(size_t i = 0; i < size; i++) {
        T temp;

        this->operator>>(temp);
        v.insert(temp);
    }

    return *this;
}

template<typename T1, typename T2>
Reader& Reader::operator>>(std::map<T1, T2>& v) {
    size_t size = 0;
    buffer->Read((char*)&size, sizeof(size_t));

    for(size_t i = 0; i < size; i++) {
        T1 key;
        T2 val;

        this->operator>>(key)>>(val);
        v.insert(std::make_pair(key, val));
    }
    return *this;
}

}
#endif
